/*
 * @Author: intellectual-seeker 3336339701@qq.com
 * @Date: 2025-03-24 16:55:05
 * @LastEditors: intellectual-seeker 3336339701@qq.com
 * @LastEditTime: 2025-08-07 20:37:48
 * @FilePath: /code/lesson25/processpool/processpool.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <cstdlib>
#include <vector>
#include <ctime>
#include <sys/wait.h>
#include "task.hpp"

using namespace std;

//匿名枚举类型
enum
{
    UsageError = 1,
    ArgError,
    PipeError
};

class Channel
{
public: 
    Channel(pid_t wfd, int sub_process_id, const string& name)
        :_wfd(wfd)
        ,_sub_process_id(sub_process_id)
        ,_name(name)
    {}

    pid_t wfd()
    {
        return _wfd;
    }

    pid_t pid()
    {
        return _sub_process_id;
    }

    string name()
    {
        return _name;
    }

    void Close()
    {
        close(_wfd);
    }

    void PrintDebug()
    {
        cout << "wfd: " << _wfd << ","
        << "sub_process_id: " << _sub_process_id << ","
        << "name: " << _name << endl;
    }

    ~Channel()
    {}
private:
    pid_t _wfd;
    int _sub_process_id;
    const std::string _name;
};

//使用手册
void Usage(const std::string& proc)
{
    cout << "Usage: " << proc << " subprocess-num" << endl;
}

class ProcessPool
{
public:
    ProcessPool(int sub_process_num)
        :_sub_process_num(sub_process_num)
    {}

    int CreateProcess(work_t work)
    {
        vector<int> fds;
        for(int i = 0; i < _sub_process_num; i++)
        {
            int pipefd[2]{0};
            int n = pipe(pipefd);
            if(n < 0) return PipeError;

            pid_t id = fork();//err: int

            if(id == 0)
            {
                if(!fds.empty())
                {
                    cout << "close w fd ";
                    for(auto& fd : fds) 
                    {
                        close(fd);
                        cout << fd << " ";
                    }
                    cout << endl;

                    //fflush(stdout);//刷新输出缓冲区
                }

                //sleep(1);

                //chlid -r
                close(pipefd[1]);
                dup2(pipefd[0], 0);//dup2(oldfd, newfd); oldfd => newfd，拷贝至newfd的位置
                work(pipefd[0]);

                exit(0);
            }

            sleep(1);

            string cname = "channel-" + std::to_string(i);

            close(pipefd[0]);

            channels.push_back(Channel(pipefd[1], id, cname));

            fds.push_back(pipefd[1]);
        }

        return 0;
    }

    void KillAll()
    {
        for(auto& channel : channels)
        {
            channel.Close();//写端没有关完
            pid_t id = channel.pid();
            pid_t rid = waitpid(id, nullptr, 0);
            if(id == rid)
            {
                cout << "wait sub process: " << id << " sucess..." << endl;
            }
            cout << channel.name() << " close done " << " sub process quit now : " << channel.pid() << endl;
        }
    }

    // void Wait()
    // {
    //     for(auto& channel : channels)
    //     {
    //         pid_t id = channel.pid();
    //         pid_t rid = waitpid(id, nullptr, 0);
    //         if(id == rid)
    //         {
    //             cout << "wait sub process: " << id << " sucess..." << endl;
    //         }
    //     }
    // }

    int NextChannel()
    {
        static int next = 0;
        int c = next;
        next++;
        next %= channels.size();
        return c;
    }

    void SendTaskCode(int index, uint32_t code)
    {
        cout << "send code: " << code << " to " << channels[index].name() << " sub process id: " << channels[index].pid() << endl;
        write(channels[index].wfd(), &code, sizeof(code));
    }

    void Debug()
    {
        for(auto& channel : channels)
        {
            channel.PrintDebug();
        }
    }

    ~ProcessPool()
    {}
    
private:
    vector<Channel> channels;
    int _sub_process_num;
};

void CtrlProcessPool(ProcessPool* processpool_ptr, int cnt)
{
    while(cnt)
    {
        int channel = processpool_ptr->NextChannel();

        //负载均衡，rs方式，轮询方式
        uint32_t code = NextTask();

        //cout << "channel: " << channel << " code: " << code << " sizeof(uint32_t): " << sizeof(uint32_t) << endl;
        processpool_ptr->SendTaskCode(channel, code);

        sleep(1);

        cnt--;
    }
}

int main(int argc, char* argv[])
{
    //.processpool 5
    if(argc != 2)
    {
        Usage(argv[0]);
        return UsageError;
    }
    
    srand((uint64_t)time(nullptr));

    //检查参数合法性
    int sub_process_num = std::stoi(argv[1]);
    if(sub_process_num <= 0) return ArgError;

    //创建子进程，同时创建管道
    ProcessPool* processpool_ptr = new ProcessPool(sub_process_num);
    processpool_ptr->CreateProcess(worker);
    //processpool_ptr->Debug();

    //控制子进程
    CtrlProcessPool(processpool_ptr, 5);

    cout << "task run done!" << endl;

    processpool_ptr->KillAll();
    
    //回收子进程
    //processpool_ptr->Wait();

    //sleep(100);

    delete processpool_ptr;

    return 0;
}